package com.fla.puzzle;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Properties;

import com.fla.puzzle.pack.Pack;
import com.fla.puzzle.pack.PackItem;
import com.fla.puzzle.utils.AndroidUtils;
import com.fla.puzzle.utils.BitmapUtils;
import com.fla.puzzle.utils.Strings;
import com.fla.puzzle.utils.Utils;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;

public class AssetsPackDataProvider implements PackDataProvider {
    private static final String PACKS_DIR = "packs";

    private static final String PACK_ITEMS_DIR = "items";

    private static final String PACK_PREVIEW_IMAGE = "preview.jpg";
    private static final String PROPERTIES_FILE_NAME = "properties.xml";

    private static final String PROPERTIES_PACK_NAME = "pack_name";
    private static final String PROPERTIES_PACK_DESCRIPTION = "pack_description";
    private static final String PROPERTIES_PACK_HD = "is_hd";
    private static final String PROPERTIES_ITEM_NAME_TEMPLATE = "%s_name";
    private static final String PROPERTIES_ITEM_DESCRIPTION_TEMPLATE = "%s_description";

    private final Context context;
    private String defaultPackName;
    private String defaultPuzzleName;

    public AssetsPackDataProvider(Context context) {
        this.context = context;
        defaultPackName = context.getResources().getString(R.string.pack_template_name);
        defaultPuzzleName = context.getResources().getString(R.string.puzzle_template_name);
    }

    @Override
    public List<Pack> loadPacks() {
        try {
            List<Pack> packs = new ArrayList<Pack>();

            List<String> sortedDirs = sort(context.getAssets().list(PACKS_DIR));
            for (String packDir : sortedDirs) {
                packs.add(loadPack(packDir));
            }
            return packs;
        }
        catch (IOException e) {
            throw new IllegalStateException("Cannot locad packs", e);
        }
    }

    @Override
    public Bitmap loadBitmap(String id) {
        InputStream is = null;
        try {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inDensity = AndroidUtils.getDisplayMetrics(context).densityDpi;

            return BitmapFactory.decodeStream(is = context.getAssets().open(id), null, options);
        }
        catch (IOException e) {
            throw new IllegalStateException("Cannot load bitmap", e);
        }
        finally {
            Utils.closeQuietly(is);
        }
    }

    @Override
    public Bitmap loadBitmap(String id, int fullWidth, int fullHeight) {
        InputStream is = null;
        try {

            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inDensity = AndroidUtils.getDisplayMetrics(context).densityDpi;
            options.inSampleSize = BitmapUtils.getSampleSize(is = context.getAssets().open(id), fullWidth, fullHeight);
            Log.d("test", "inSampleSize: " + options.inSampleSize);
            Utils.closeQuietly(is);
            return BitmapFactory.decodeStream(is = context.getAssets().open(id), null, options);
        }
        catch (IOException e) {
            throw new IllegalStateException("Cannot load bitmap", e);
        }
        finally {
            Utils.closeQuietly(is);
        }
    }

    @Override
    public InputStream loadInputStream(String id) {
        try {
            return context.getAssets().open(id);
        }
        catch (IOException e) {
            throw new IllegalStateException("Cannot load bitmap", e);
        }
    }

    private List<String> sort(String[] names) {
        List<String> result = new ArrayList<String>(Arrays.asList(names));
        Collections.sort(result, Strings.getNaturalComparator());
        return result;
    }

    private Pack loadPack(String packDir) throws IOException {
        Properties properties = loadProperties(createPathInPack(packDir, PROPERTIES_FILE_NAME));

        Pack pack = new Pack();

        pack.setId(packDir);
        pack.setPreviewImageId(createPathInPack(packDir, PACK_PREVIEW_IMAGE));
        pack.setName(properties.getProperty(PROPERTIES_PACK_NAME, packDir).replaceFirst("%s", defaultPackName));
        pack.setDescription(properties.getProperty(PROPERTIES_PACK_DESCRIPTION));
        pack.setHd(Boolean.valueOf(properties.getProperty(PROPERTIES_PACK_HD, "false")));

        List<String> sortedItems = sort(context.getAssets().list(createPathInPack(packDir, PACK_ITEMS_DIR)));
        for (String item : sortedItems) {
            PackItem packItem = new PackItem(item, packDir);

            String itemName = removeExtention(item);

            String itemPropertyName = String.format(PROPERTIES_ITEM_NAME_TEMPLATE, itemName);
            packItem.setName(properties.getProperty(itemPropertyName, itemName).replaceFirst("%s", defaultPuzzleName));
            packItem.setDescription(properties.getProperty(String.format(PROPERTIES_ITEM_DESCRIPTION_TEMPLATE, itemName)));
            packItem.setImageId(createPathInPack(packDir, PACK_ITEMS_DIR) + File.separator + item);

            pack.addPackItem(packItem);
        }
        return pack;
    }

    private String removeExtention(String fileName) {
        return fileName.substring(0, fileName.lastIndexOf("."));
    }

    private String createPathInPack(String packDir, String fileName) {
        return PACKS_DIR + File.separator + packDir + File.separator + fileName;
    }

    private Properties loadProperties(String propertiesPath) throws IOException {
        InputStream inputStream = null;
        try {
            Properties properties = new Properties();
            properties.loadFromXML(inputStream = context.getAssets().open(propertiesPath));
            return properties;
        }
        catch (FileNotFoundException e) {
            Log.w("AssetsPackDataProvider", "Properties file not found: " + propertiesPath);
            return new Properties();
        }
        finally {
            Utils.closeQuietly(inputStream);
        }
    }
}
